/**
 * Copyright (c) 2013 onionframework.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.onionframework.servlet;

import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.Servlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;

import org.apache.commons.collections4.comparators.ComparatorChain;
import org.apache.commons.lang3.StringUtils;
import org.onionframework.core.util.Exceptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoaderListener;

/**
 * @author allan
 *
 */
@WebListener
public class OnionContextLoaderListener extends ContextLoaderListener{

	private Logger logger = LoggerFactory.getLogger(OnionContextLoaderListener.class);
	
	public void contextInitialized(ServletContextEvent event) {
		super.contextInitialized(event);
		this.initFilters(event);
		this.initServlets(event);
	}

	/**
	 * @param event
	 */
	private void initServlets(ServletContextEvent event) {
		Map<String,Object> annotatedServlets = super.getCurrentWebApplicationContext().getBeansWithAnnotation(OnionServlet.class);
		
		Servlet servlet;
		ServletRegistration.Dynamic dynamicServlet;
		OnionServlet annotation;
		for(Map.Entry<String, Object> entry : annotatedServlets.entrySet()){
			if(!(entry.getValue() instanceof Servlet)){
				throw Exceptions.system("错误的Servlet定义：" + entry.getValue().getClass().toString(), null);
			}

			servlet = (Servlet)entry.getValue();
			annotation = servlet.getClass().getAnnotation(OnionServlet.class);
			dynamicServlet = event.getServletContext().addServlet(entry.getKey(), servlet);
			dynamicServlet.addMapping(annotation.urlPatterns());
			
			logger.info("加载了Servlet {}", entry.getValue().getClass().toString());
		}
		
		//加入ServletDelegate对应的Servlets
		Map<String,ServletDelegate> delegates = super.getCurrentWebApplicationContext().getBeansOfType(ServletDelegate.class);
		
		for(Map.Entry<String, ServletDelegate> entry : delegates.entrySet()){
			servlet = entry.getValue().getTarget();
			dynamicServlet = event.getServletContext().addServlet(entry.getKey(), servlet);
			dynamicServlet.addMapping(entry.getValue().getUrlPatterns());
			
			logger.info("加载了Servlet {}",servlet.getClass().toString());
		}
	}

	/**
	 * @param event
	 */
	private void initFilters(ServletContextEvent event) {
		Map<String,Object> filterBeans = super.getCurrentWebApplicationContext().getBeansWithAnnotation(OnionFilter.class);
		
		Set<FilterDelegate> filters = new TreeSet<FilterDelegate>(new ComparatorChain<FilterDelegate>(){

			private static final long serialVersionUID = 1742407857366814506L;

			@Override
			public int compare(FilterDelegate o1, FilterDelegate o2) {
				int result = o1.getIndex() - o2.getIndex();
				return result == 0 ? 1 : result;
			}
		});
		
		OnionFilter annotation;
		String name;
		for(Object filter : filterBeans.values()){
			if(!(filter instanceof Filter)){
				throw Exceptions.system("错误的Filter定义：" + filter.getClass().toString(), null);
			}
			annotation = filter.getClass().getAnnotation(OnionFilter.class);
			name = annotation.value();
			if(StringUtils.isBlank(name))
				name = filter.getClass().getSimpleName();
			filters.add(new FilterDelegate((Filter)filter, annotation.urlPatterns(), annotation.index(),name));
		}
		
		//加入FilterDelegate对应的Filters
		Map<String,FilterDelegate> delegates = super.getCurrentWebApplicationContext().getBeansOfType(FilterDelegate.class);
		
		for(Map.Entry<String, FilterDelegate> entry : delegates.entrySet()){
			filters.add(entry.getValue());
		}
		
		FilterRegistration.Dynamic dynamicFilter;
		for(FilterDelegate delegate : filters){
			dynamicFilter = event.getServletContext().addFilter(delegate.getName(), delegate.getTarget());
			dynamicFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, delegate.getUrlPatterns());
			
			logger.info("加载了Filter {},index={}", delegate.getTarget().getClass().toString(),delegate.getIndex());
		}
	}
	
}
